package com.xunk.equipment.filter;

import com.xunk.common.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.zip.GZIPInputStream;

/**
 * @ProjectName: HIM
 * @Package: com.xunk.equipment.filter
 * @ClassName: GzipDecompressFilter
 * @Author: luanzhiwei
 * @Description: 解压缩gzip过滤器
 * @Date: 2021/6/29 15:36
 * @Version: 1.0
 */
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GzipDecompressFilter extends OncePerRequestFilter {


    /**
     * Same contract as for {@code doFilter}, but guaranteed to be
     * just invoked once per request within a single request thread.
     * See {@link #shouldNotFilterAsyncDispatch()} for details.
     * <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
     * default ServletRequest and ServletResponse ones.
     *
     * @param request
     * @param response
     * @param filterChain
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(new HttpServletRequestWrapper(request), response);
    }

    class HttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper {
        private HttpServletRequest request;

        public HttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
            this.request = request;
        }

        /**
         * 根据 request header 的 Content-Encoding 判断是否启用 gzip 解压数据流
         *
         * @return
         * @throws IOException
         */
        @Override
        public ServletInputStream getInputStream() throws IOException {
            ServletInputStream stream = request.getInputStream();

            //压缩标识
            boolean gzipFlag = false;
            final HttpServletRequest httpServletRequest = request;
            for (Enumeration<String> enumeration = httpServletRequest.getHeaderNames(); enumeration.hasMoreElements(); ) {
                String name = enumeration.nextElement();
                String contentEncoding;
                if (name.equalsIgnoreCase("content-encoding")
                        && StringUtils.isNotEmpty(contentEncoding = httpServletRequest.getHeader(name))
                        && contentEncoding.indexOf("gzip") != -1) {
                    gzipFlag = true;
                }
            }
            if (gzipFlag) {
                try {
                    log.info("存在gzip压缩请求，开始解压");
                    GZIPInputStream gzipInputStream = new GZIPInputStream(request.getInputStream());
                    return new ServletInputStream() {

                        @Override
                        public int read() throws IOException {
                            return gzipInputStream.read();
                        }

                        @Override
                        public boolean isFinished() {
                            return false;
                        }

                        @Override
                        public boolean isReady() {
                            return false;
                        }

                        @Override
                        public void setReadListener(ReadListener readListener) {

                        }
                    };
                } catch (Exception e) {
                    log.error("uncompress content fail.", e);
                }
            }

            return stream;
        }
    }
}
